package dk.pun.dums.client.view;


import java.util.Comparator;
import java.util.List;

import com.google.gwt.cell.client.ActionCell;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.cell.client.SelectionCell;
import com.google.gwt.cell.client.TextCell;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.uibinder.client.UiTemplate;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.ColumnSortEvent;
import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.ListDataProvider;

import dk.pun.dums.client.widget.CharacterRenameDialog;
import dk.pun.dums.client.widget.DeleteCharacterDialog;
import dk.pun.dums.shared.character.CharacterData;
import dk.pun.dums.shared.character.CharacterStatus;

public class SelectCharacterViewImpl extends Composite implements SelectCharacterView {

	private static SelectCharacterViewUiBinder uiBinder = GWT.create(SelectCharacterViewUiBinder.class);

	@UiTemplate("SelectCharacterView.ui.xml")
	interface SelectCharacterViewUiBinder extends UiBinder<Widget, SelectCharacterViewImpl> {}

	@UiField protected transient CellTable<CharacterData> characterTable;
	@UiField protected transient TextBox newCharacterName;
	@UiField protected transient Button newCharacterButton;
	
	private transient Presenter presenter;
	private transient ListDataProvider<CharacterData> listDataProvider;
	private transient ColumnSortEvent columnSortEvent;
	
	public SelectCharacterViewImpl() {
		super();
		initWidget(uiBinder.createAndBindUi(this));
		this.initCharacterTable();
	}
	
	private void initCharacterTable() {
		this.characterTable.setPageSize(10);

		final ActionCell<CharacterData> viewButtonCell = new ActionCell<CharacterData>("Vis",
				new ActionCell.Delegate<CharacterData>() {
					@Override
					public void execute(final CharacterData characterData) {
						presenter.onCharacterSelected(characterData);
					}
				});		
		final Column<CharacterData, CharacterData> viewButtonColumn = new Column<CharacterData, CharacterData>(viewButtonCell) {
			@Override
			public CharacterData getValue(final CharacterData characterData) {
				return characterData;
			}
		};
		this.characterTable.addColumn(viewButtonColumn);
		this.characterTable.setColumnWidth(viewButtonColumn, 50, Unit.PX);
			
		final Column<CharacterData, String> nameColumn = new Column<CharacterData, String>(new TextCell()) {
			@Override
			public String getValue(final CharacterData characterData) {
				return characterData.getName();
			}
		};
		//nameColumn.setSortable(true);
		this.characterTable.addColumn(nameColumn, "Navn");

		final Column<CharacterData, String> statusColumn = new Column<CharacterData, String>(new SelectionCell(CharacterStatus.NAMES)) {
			@Override
			public String getValue(final CharacterData characterData) {
				return characterData.getStatus().getName();
			}
		};
		statusColumn.setFieldUpdater(new FieldUpdater<CharacterData, String>() {
			@Override
			public void update(final int index, final CharacterData characterData, final String statusName) {
				for (CharacterStatus status : CharacterStatus.values()) {
					if (status.getName().equals(statusName)) {
						characterData.setStatus(status);
						presenter.onCharacterStatusUpdated(characterData);
						sortTable();
					}
				}
			}
		});
		//statusColumn.setSortable(true);
		this.characterTable.addColumn(statusColumn, "Status");
		this.characterTable.setColumnWidth(statusColumn, 50, Unit.PX);

		final ActionCell<CharacterData> renameButtonCell = new ActionCell<CharacterData>("Omdøb",
				new ActionCell.Delegate<CharacterData>() {
					@Override
					public void execute(final CharacterData characterData) {
						final CharacterRenameDialog characterRenameDialog = new CharacterRenameDialog(presenter, characterData);
						characterRenameDialog.show();
						characterRenameDialog.center();
					}
				});
		final Column<CharacterData, CharacterData> renameButtonColumn = new Column<CharacterData, CharacterData>(renameButtonCell) {
			@Override
			public CharacterData getValue(final CharacterData characterData) {
				return characterData;
			}
		};
		this.characterTable.addColumn(renameButtonColumn);
		this.characterTable.setColumnWidth(renameButtonColumn, 50, Unit.PX);

		final ActionCell<CharacterData> deleteButtonCell = new ActionCell<CharacterData>("Slet",
				new ActionCell.Delegate<CharacterData>() {
					@Override
					public void execute(final CharacterData characterData) {
						final DeleteCharacterDialog deleteCharacterDialog = new DeleteCharacterDialog(presenter, characterData);
						deleteCharacterDialog.show();
						deleteCharacterDialog.center();
					}
				});
		final Column<CharacterData, CharacterData> deleteButtonColumn = new Column<CharacterData, CharacterData>(deleteButtonCell) {
			@Override
			public CharacterData getValue(final CharacterData characterData) {
				return characterData;
			}
		};
		this.characterTable.addColumn(deleteButtonColumn);
		this.characterTable.setColumnWidth(deleteButtonColumn, 50, Unit.PX);
		
		this.listDataProvider = new ListDataProvider<CharacterData>();
		this.listDataProvider.addDataDisplay(this.characterTable);
		
		ListHandler<CharacterData> nameColumnSortHandler = new ListHandler<CharacterData>(this.listDataProvider.getList());
		nameColumnSortHandler.setComparator(nameColumn, new Comparator<CharacterData>() {
			
			@Override
			public int compare(CharacterData cd1, CharacterData cd2) {
				int result;
				if (cd1 != null) {
					if (cd2 != null) {
						result = cd1.getName().compareToIgnoreCase(cd2.getName());
					} else {
						result = 1;
					}
				} else {
					result = -1;
				}
				return result;
			}
		});
		this.characterTable.addColumnSortHandler(nameColumnSortHandler);
		this.characterTable.getColumnSortList().push(nameColumn);
		
		ListHandler<CharacterData> statusColumnSortHandler = new ListHandler<CharacterData>(this.listDataProvider.getList());
		statusColumnSortHandler.setComparator(statusColumn, new Comparator<CharacterData>() {

			@Override
			public int compare(CharacterData cd1, CharacterData cd2) {
				int result;
				if (cd1 != null) {
					if (cd2 != null) {
						result = cd1.getStatus().compareTo(cd2.getStatus());
						if (result == 0) {
							result = cd1.getName().compareToIgnoreCase(cd2.getName());
						}
					} else {
						result = 1;
					}
				} else {
					result = -1;
				}
				return result;
			}
		});
		this.characterTable.addColumnSortHandler(statusColumnSortHandler);
		this.characterTable.getColumnSortList().push(statusColumn);
		
		this.columnSortEvent = new ColumnSortEvent(this.characterTable.getColumnSortList()) {};
	}

	@Override
	public void setCharacters(final List<CharacterData> characterDataList) {
		final List<CharacterData> list = this.listDataProvider.getList();
		list.clear();
		for (CharacterData characterData : characterDataList) {
			list.add(characterData);
		}
		this.sortTable();
	}
	
	@Override
	public void addCharacter(CharacterData characterData) {
		this.listDataProvider.getList().add(characterData);
		this.sortTable();
	}

	@Override
	public void removeCharacter(CharacterData characterData) {
		this.listDataProvider.getList().remove(characterData);
	}
	
	@Override
	public void refreshCharacterView() {
		this.listDataProvider.refresh();
		this.sortTable();
	}

	private void sortTable() {
		this.characterTable.fireEvent(this.columnSortEvent);		
	}
	
	@Override
	public void setPresenter(final Presenter presenter) {
		this.presenter = presenter;
	}
		
	@UiHandler("newCharacterButton")
	public void characterButtonClicked(final ClickEvent event) {
		final String newName = this.newCharacterName.getText();
		this.newCharacterName.setText("");
		if (this.presenter != null && !newName.isEmpty()) {
			this.presenter.onCharacterAdded(newName);
		}
	}
	
	@UiHandler("newCharacterName")
	public void characterNameKeyPressed(final KeyPressEvent event) {
		if (KeyCodes.KEY_ENTER == event.getNativeEvent().getKeyCode()) {
			final String newName = this.newCharacterName.getText();
			this.newCharacterName.setText("");
			if (this.presenter != null && !newName.isEmpty()) {
				this.presenter.onCharacterAdded(newName);
			}
		}
	}
	
	@Override
	public Widget asWidget() {
		return this;
	}
}
